{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "10882c61",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PreTrainedTokenizerFast(name_or_path='distilbert-base-uncased', vocab_size=30522, model_max_len=512, is_fast=True, padding_side='right', truncation_side='right', special_tokens={'unk_token': '[UNK]', 'sep_token': '[SEP]', 'pad_token': '[PAD]', 'cls_token': '[CLS]', 'mask_token': '[MASK]'})\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'input_ids': [[101, 5342, 2047, 3595, 8496, 2013, 1996, 18643, 3197, 102], [101, 3397, 2053, 15966, 1010, 2069, 4450, 2098, 18201, 2015, 102]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]}"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from transformers import AutoTokenizer\n",
    "\n",
    "#加载编码器\n",
    "tokenizer = AutoTokenizer.from_pretrained('distilbert-base-uncased',\n",
    "                                          use_fast=True)\n",
    "\n",
    "print(tokenizer)\n",
    "\n",
    "#编码试算\n",
    "tokenizer.batch_encode_plus([\n",
    "    'hide new secretions from the parental units',\n",
    "    'contains no wit , only labored gags'\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ab08bc4c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Loading cached processed dataset at datas/glue/cola/train/cache-6def1c5f8a327c94.arrow\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Loading cached processed dataset at datas/glue/cola/train/cache-31d27e0837d27207.arrow\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Loading cached processed dataset at datas/glue/cola/train/cache-2f99156118cc2a5d.arrow\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Loading cached processed dataset at datas/glue/cola/train/cache-89989a31ab1075b6.arrow\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Loading cached processed dataset at datas/glue/cola/validation/cache-6b7c3e2e8bff6006.arrow\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Loading cached processed dataset at datas/glue/cola/validation/cache-dd12b7baf47b5578.arrow\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Loading cached processed dataset at datas/glue/cola/validation/cache-857d56c2dc1f0ef3.arrow\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Loading cached processed dataset at datas/glue/cola/validation/cache-c2a54676cfb020f7.arrow\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Loading cached processed dataset at datas/glue/cola/test/cache-fe1d9a8362ec0a58.arrow\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Loading cached processed dataset at datas/glue/cola/test/cache-301de2aa72a796c4.arrow\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Loading cached processed dataset at datas/glue/cola/test/cache-ba8c1110f769f8ff.arrow\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " "
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Loading cached processed dataset at datas/glue/cola/test/cache-8e279bffbe110091.arrow\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'label': 1, 'input_ids': [101, 2256, 2814, 2180, 1005, 1056, 4965, 2023, 4106, 1010, 2292, 2894, 1996, 2279, 2028, 2057, 16599, 1012, 102], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "DatasetDict({\n",
       "    train: Dataset({\n",
       "        features: ['label', 'input_ids', 'attention_mask'],\n",
       "        num_rows: 8551\n",
       "    })\n",
       "    validation: Dataset({\n",
       "        features: ['label', 'input_ids', 'attention_mask'],\n",
       "        num_rows: 1043\n",
       "    })\n",
       "    test: Dataset({\n",
       "        features: ['label', 'input_ids', 'attention_mask'],\n",
       "        num_rows: 1063\n",
       "    })\n",
       "})"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from datasets import load_dataset, load_from_disk\n",
    "\n",
    "#加载数据\n",
    "#dataset = load_dataset(path='glue', name='cola')\n",
    "dataset = load_from_disk('datas/glue/cola')\n",
    "\n",
    "\n",
    "#分词,同时删除多余的字段\n",
    "def f(examples):\n",
    "    return tokenizer.batch_encode_plus(examples['sentence'], truncation=True)\n",
    "\n",
    "\n",
    "dataset = dataset.map(function=f,\n",
    "                      batched=True,\n",
    "                      batch_size=1000,\n",
    "                      num_proc=4,\n",
    "                      remove_columns=['sentence', 'idx'])\n",
    "\n",
    "print(dataset['train'][0])\n",
    "\n",
    "dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "1d8fa0a0",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "input_ids torch.Size([8, 17]) tensor([[  101,  1996,  2062,  2008,  2017,  4521,  1010,  1996,  2625,  2008,\n",
      "          2017,  2215,  1012,   102,     0,     0,     0],\n",
      "        [  101,  2029,  4905,  2097,  2507,  1996,  5494,  6685,  8440,  1005,\n",
      "          1056,  2042,  2787,  2011,  2068,  1012,   102],\n",
      "        [  101,  1045,  2052,  3153,  2007, 10334,  1012,   102,     0,     0,\n",
      "             0,     0,     0,     0,     0,     0,     0]])\n",
      "attention_mask torch.Size([8, 17]) tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],\n",
      "        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],\n",
      "        [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]])\n",
      "labels torch.Size([8]) tensor([1, 1, 1])\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "1068"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "from transformers.data.data_collator import DataCollatorWithPadding\n",
    "\n",
    "#数据加载器\n",
    "loader = torch.utils.data.DataLoader(\n",
    "    dataset=dataset['train'],\n",
    "    batch_size=8,\n",
    "    collate_fn=DataCollatorWithPadding(tokenizer),\n",
    "    shuffle=True,\n",
    "    drop_last=True,\n",
    ")\n",
    "\n",
    "for i, data in enumerate(loader):\n",
    "    break\n",
    "\n",
    "for k, v in data.items():\n",
    "    print(k, v.shape, v[:3])\n",
    "\n",
    "len(loader)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "bf284aa8",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Some weights of the model checkpoint at distilbert-base-uncased were not used when initializing DistilBertModel: ['vocab_layer_norm.weight', 'vocab_layer_norm.bias', 'vocab_transform.bias', 'vocab_projector.bias', 'vocab_projector.weight', 'vocab_transform.weight']\n",
      "- This IS expected if you are initializing DistilBertModel from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n",
      "- This IS NOT expected if you are initializing DistilBertModel from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n",
      "Some weights of the model checkpoint at distilbert-base-uncased were not used when initializing DistilBertForSequenceClassification: ['vocab_layer_norm.weight', 'vocab_layer_norm.bias', 'vocab_transform.bias', 'vocab_projector.bias', 'vocab_projector.weight', 'vocab_transform.weight']\n",
      "- This IS expected if you are initializing DistilBertForSequenceClassification from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n",
      "- This IS NOT expected if you are initializing DistilBertForSequenceClassification from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n",
      "Some weights of DistilBertForSequenceClassification were not initialized from the model checkpoint at distilbert-base-uncased and are newly initialized: ['classifier.weight', 'classifier.bias', 'pre_classifier.weight', 'pre_classifier.bias']\n",
      "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6695.501\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "(tensor(0.6933, grad_fn=<NllLossBackward0>), torch.Size([8, 2]))"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from transformers import AutoModelForSequenceClassification, DistilBertModel\n",
    "\n",
    "#加载模型\n",
    "#model = AutoModelForSequenceClassification.from_pretrained('distilbert-base-uncased', num_labels=2)\n",
    "\n",
    "\n",
    "#定义下游任务模型\n",
    "class Model(torch.nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.pretrained = DistilBertModel.from_pretrained(\n",
    "            'distilbert-base-uncased')\n",
    "\n",
    "        self.fc = torch.nn.Sequential(torch.nn.Linear(768, 768),\n",
    "                                      torch.nn.ReLU(), torch.nn.Dropout(p=0.2),\n",
    "                                      torch.nn.Linear(768, 2))\n",
    "\n",
    "        #加载预训练模型的参数\n",
    "        parameters = AutoModelForSequenceClassification.from_pretrained(\n",
    "            'distilbert-base-uncased', num_labels=2)\n",
    "        self.fc[0].load_state_dict(parameters.pre_classifier.state_dict())\n",
    "        self.fc[3].load_state_dict(parameters.classifier.state_dict())\n",
    "\n",
    "        self.criterion = torch.nn.CrossEntropyLoss()\n",
    "\n",
    "    def forward(self, input_ids, attention_mask, labels=None):\n",
    "        logits = self.pretrained(input_ids=input_ids,\n",
    "                                 attention_mask=attention_mask)\n",
    "        logits = logits.last_hidden_state[:, 0]\n",
    "        logits = self.fc(logits)\n",
    "\n",
    "        loss = None\n",
    "        if labels is not None:\n",
    "            loss = self.criterion(logits, labels)\n",
    "\n",
    "        return {'loss': loss, 'logits': logits}\n",
    "\n",
    "\n",
    "model = Model()\n",
    "\n",
    "#统计参数量\n",
    "print(sum(i.numel() for i in model.parameters()) / 10000)\n",
    "\n",
    "out = model(**data)\n",
    "\n",
    "out['loss'], out['logits'].shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "cb185057",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using the latest cached version of the module from /root/.cache/huggingface/modules/datasets_modules/metrics/glue/91f3cfc5498873918ecf119dbf806fb10815786c84f41b85a5d3c47c1519b343 (last modified on Mon Jul 11 13:08:31 2022) since it couldn't be found locally at glue, or remotely on the Hugging Face Hub.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'matthews_correlation': 0.5773502691896258}"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from datasets import load_metric\n",
    "\n",
    "#加载评价函数\n",
    "metric = load_metric(path='glue', config_name='cola')\n",
    "\n",
    "#试算\n",
    "metric.compute(predictions=[0, 1, 1, 0], references=[0, 1, 1, 1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "af27b8b0",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "10\n",
      "20\n",
      "30\n",
      "40\n",
      "50\n",
      "0.6446078431372549 {'matthews_correlation': 0.013769908528691366}\n"
     ]
    }
   ],
   "source": [
    "#测试\n",
    "def test():\n",
    "    model.eval()\n",
    "\n",
    "    #数据加载器\n",
    "    loader_test = torch.utils.data.DataLoader(\n",
    "        dataset=dataset['validation'],\n",
    "        batch_size=16,\n",
    "        collate_fn=DataCollatorWithPadding(tokenizer),\n",
    "        shuffle=True,\n",
    "        drop_last=True,\n",
    "    )\n",
    "\n",
    "    outs = []\n",
    "    labels = []\n",
    "    for i, data in enumerate(loader_test):\n",
    "        #计算\n",
    "        with torch.no_grad():\n",
    "            out = model(**data)\n",
    "\n",
    "        outs.append(out['logits'].argmax(dim=1))\n",
    "        labels.append(data['labels'])\n",
    "\n",
    "        if i % 10 == 0:\n",
    "            print(i)\n",
    "\n",
    "        if i == 50:\n",
    "            break\n",
    "\n",
    "    outs = torch.cat(outs)\n",
    "    labels = torch.cat(labels)\n",
    "\n",
    "    accuracy = (outs == labels).sum().item() / len(labels)\n",
    "    metric_out = metric.compute(predictions=outs, references=labels)\n",
    "\n",
    "    print(accuracy, metric_out)\n",
    "\n",
    "\n",
    "test()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "ed013a1a",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/root/anaconda3/envs/cpu/lib/python3.6/site-packages/transformers/optimization.py:309: FutureWarning: This implementation of AdamW is deprecated and will be removed in a future version. Use the PyTorch implementation torch.optim.AdamW instead, or set `no_deprecation_warning=True` to disable this warning\n",
      "  FutureWarning,\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 0.6523979902267456 0.75 {'matthews_correlation': 0.3333333333333333} 1.9981273408239703e-05\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/root/anaconda3/envs/cpu/lib/python3.6/site-packages/sklearn/metrics/_classification.py:873: RuntimeWarning: invalid value encountered in double_scalars\n",
      "  mcc = cov_ytyp / np.sqrt(cov_ytyt * cov_ypyp)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "50 0.6507331728935242 0.625 {'matthews_correlation': 0.0} 1.9044943820224723e-05\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/root/anaconda3/envs/cpu/lib/python3.6/site-packages/sklearn/metrics/_classification.py:873: RuntimeWarning: invalid value encountered in double_scalars\n",
      "  mcc = cov_ytyp / np.sqrt(cov_ytyt * cov_ypyp)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "100 0.7072427272796631 0.5 {'matthews_correlation': 0.0} 1.810861423220974e-05\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/root/anaconda3/envs/cpu/lib/python3.6/site-packages/sklearn/metrics/_classification.py:873: RuntimeWarning: invalid value encountered in double_scalars\n",
      "  mcc = cov_ytyp / np.sqrt(cov_ytyt * cov_ypyp)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "150 0.4458800256252289 0.75 {'matthews_correlation': 0.0} 1.7172284644194758e-05\n",
      "200 0.3876158595085144 0.75 {'matthews_correlation': -0.14285714285714285} 1.6235955056179777e-05\n",
      "250 0.49931180477142334 0.625 {'matthews_correlation': 0.14907119849998599} 1.5299625468164797e-05\n",
      "300 0.3381071388721466 0.875 {'matthews_correlation': 0.7453559924999299} 1.4363295880149814e-05\n",
      "350 0.5246998071670532 0.75 {'matthews_correlation': -0.14285714285714285} 1.3426966292134834e-05\n",
      "400 0.3265834152698517 0.75 {'matthews_correlation': 0.4879500364742666} 1.2490636704119851e-05\n",
      "450 0.6134941577911377 0.625 {'matthews_correlation': 0.14907119849998599} 1.155430711610487e-05\n",
      "500 0.6472000479698181 0.75 {'matthews_correlation': 0.5} 1.0617977528089888e-05\n",
      "550 0.5875465273857117 0.5 {'matthews_correlation': 0.0} 9.681647940074908e-06\n",
      "600 0.5096354484558105 0.875 {'matthews_correlation': 0.7745966692414834} 8.745318352059925e-06\n",
      "650 0.3630077540874481 0.75 {'matthews_correlation': -0.14285714285714285} 7.808988764044945e-06\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/root/anaconda3/envs/cpu/lib/python3.6/site-packages/sklearn/metrics/_classification.py:873: RuntimeWarning: invalid value encountered in double_scalars\n",
      "  mcc = cov_ytyp / np.sqrt(cov_ytyt * cov_ypyp)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "700 0.43435221910476685 0.75 {'matthews_correlation': 0.0} 6.872659176029963e-06\n",
      "750 0.295941561460495 0.875 {'matthews_correlation': 0.7745966692414834} 5.936329588014982e-06\n",
      "800 0.4042346477508545 0.75 {'matthews_correlation': 0.4879500364742666} 5e-06\n",
      "850 0.46937647461891174 0.75 {'matthews_correlation': -0.14285714285714285} 4.063670411985019e-06\n",
      "900 0.8482968807220459 0.5 {'matthews_correlation': -0.29277002188455997} 3.1273408239700374e-06\n",
      "950 0.4539779722690582 0.875 {'matthews_correlation': 0.7453559924999299} 2.1910112359550564e-06\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/root/anaconda3/envs/cpu/lib/python3.6/site-packages/sklearn/metrics/_classification.py:873: RuntimeWarning: invalid value encountered in double_scalars\n",
      "  mcc = cov_ytyp / np.sqrt(cov_ytyt * cov_ypyp)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000 0.1318509876728058 1.0 {'matthews_correlation': 0.0} 1.2546816479400751e-06\n",
      "1050 0.3866274952888489 0.75 {'matthews_correlation': -0.14285714285714285} 3.183520599250937e-07\n"
     ]
    }
   ],
   "source": [
    "from transformers import AdamW\n",
    "from transformers.optimization import get_scheduler\n",
    "\n",
    "\n",
    "#训练\n",
    "def train():\n",
    "    optimizer = AdamW(model.parameters(), lr=2e-5)\n",
    "    scheduler = get_scheduler(name='linear',\n",
    "                              num_warmup_steps=0,\n",
    "                              num_training_steps=len(loader),\n",
    "                              optimizer=optimizer)\n",
    "\n",
    "    model.train()\n",
    "    for i, data in enumerate(loader):\n",
    "        out = model(**data)\n",
    "        loss = out['loss']\n",
    "\n",
    "        loss.backward()\n",
    "        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)\n",
    "\n",
    "        optimizer.step()\n",
    "        scheduler.step()\n",
    "\n",
    "        optimizer.zero_grad()\n",
    "        model.zero_grad()\n",
    "\n",
    "        if i % 50 == 0:\n",
    "            out = out['logits'].argmax(dim=1)\n",
    "\n",
    "            accuracy = (data['labels'] == out).sum().item() / 8\n",
    "            metric_out = metric.compute(predictions=out,\n",
    "                                        references=data['labels'])\n",
    "\n",
    "            lr = optimizer.state_dict()['param_groups'][0]['lr']\n",
    "\n",
    "            print(i, loss.item(), accuracy, metric_out, lr)\n",
    "\n",
    "    torch.save(model, 'models/5.分类.model')\n",
    "\n",
    "\n",
    "train()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "8b737e03",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "10\n",
      "20\n",
      "30\n",
      "40\n",
      "50\n",
      "0.7769607843137255 {'matthews_correlation': 0.4382819245206996}\n"
     ]
    }
   ],
   "source": [
    "model = torch.load('models/5.分类.model')\n",
    "test()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
